/**
 * @widoc $.fn.initDropSel
 * @namespace comp
 * @des 初始化下拉复选框（禁止输入），调用此方法的文本框不需定义 name，即使定义也不可与 opts.name 相同
 * @type function
 * @param {object} opts 配置参数
 * @param {string} opts.name 必须，下拉框中复选/单选元素的 name 属性值，初始化完成后，会在 el 后生成 <input type="hidden" name="name" />，以便表单取值
 * @param {Array} opts.data 必须，选项数据源
 * @param {string=} opts.txtField data 中每个数据显示的字段名称，默认为 'name'
 * @param {string=} opts.valField data 中每个数据值的字段名称，默认为 'val'
 * @param {object} opts.filter 过滤功能配置，定义此属性后将开启过滤，生成过滤文本框
 * @param {string|Array} opts.filter.fields 参与过滤的列的属性名，对应 cols[i].field
 * @param {boolean} opts.filter.pySupport 是否支持拼音首字过滤，开启过滤时，默认为 true
 * @param {string=} opts.filter.placeholder 过滤搜索框占位符(不支持IE8,9)
 * @param {boolean} opts.filterPrepose 是否将匹配的过滤项前置，开启过滤时，默认为 false，设为 true 将增加 dom 操作，引起资源的消耗
 * @param {int=} opts.width 弹出框的宽度，单位：px，默认为 205（css 中由.dropSel 决定）
 * @param {int=} opts.height 默认最大高度为 120，单位：px
 * @param {boolean=} opts.mulChk 是否为复选，默认为 true
 * @param {Array=} opts.selParams 默认选中项条件 [key,value]，其中 value 支持 Array
 * @param {function(selData)=} opts.callback 值改变时的回调方法
 *       selData 单选时为选中项的数据对象，无选中则为 undefined；多选时为选中对象数组，无选中则为 []
 * @param {object} opts.dpOpts 下拉弹出框的初始参数，参考 $.fn.dropdown(opts)
 *       其中部分参数默认值不同：
 *         opts.dpOpts.modal 默认值为 false，即默认为非模态下拉框。
 *       其中部分参数失效：
 *         opts.dpOpts.cont 组件自动生成
 *         opts.dpOpts.noDestroy 始终为 true
 *         opts.dpOpts.show 始终为 false
 *         opts.dpOpts.beforeClose 组件中处理
 *         opts.dpOpts.beforeShow 组件中处理
 * @param {string} opts.cusCls 附加在弹出层 dropdown dropSel 层的用户自定义样式名
 * @return {object} obj 返回对象
 * @rtn {function} obj.setData(data,selParams) 重置数据源及默认选中项
 * @rtn {function} obj.getSelect() 获取选中项，返回值：selData 单选时为选中项的数据对象，无选中则为 undefined；多选时为选中对象数组，无选中则为 []
 * @rtn {function} obj.check(key,val,check) 改变符合条件的数据源的选中状态，并更新到 dom 和 selIdx
 *       key {string=} 键
 *       val {string|Array|undefined=} 值
 *       check {boolean=} 选中 true / 取消选中 false，默认为 true
 */
$.fn.initDropSel=function(opts){
    var CONF={emptyH:32};// 没有选项时的高度
    var el=$(this);// 触发下拉的元素
    opts=$.extend({
        //width:0,// 弹出框的宽度
        height:150 // 默认高度为 150px
        ,mulChk:true // 默认为复选
        //            ,name:'' // 必须，下拉框中复选/单选元素的 name 属性值，初始化完成后，会在 el 后生成 <input type="hidden" name="name" />，以便表单取值
        ,data:[] // 数据源
        ,txtField:'name' // data 中每个数据显示的字段名称
        ,valField:'val' // data 中每个数据值的字段名称
        //,filter:{} // 过滤配置
        ,filterPrepose:false// 开启过滤时，是否将过滤匹配项前置
        ,dpOpts:{}// dropdown 扩展配置
        ,cusCls:''// 给dropdown dropSel层添加class，用于自定义样式
        //        ,selParams: [key,value] // 第一次弹出的选中项条件[key,value]，value 支持数组
        //        ,callback: function(selData) // 确定按钮的回调，单选时为选中项的数据对象，无选中则为 undefined；多选时为选中对象数组，无选中则为 []
    },opts);
    var guid=$.generateGuid('dropSel');
    !opts.name && (opts.name=guid);
    var hideEl;// 隐藏元素，用于表单取值
    var _data
        ,returnObj;// 返回对象
    var dpObj// dropdown 返回接口
        ,_filterObj// 过滤组件返回接口对象
        ,dpEl// 下拉弹出层 jquery 对象
        ,selIdx=[];// 选中的项的索引
    // 根据 dom 选中状态获取选中项
    var _refreshSelIdx=function(){
        selIdx.length=0;
        var chkEls=dpEl.find('[name="'+opts.name+'"]:checked');
        var txtField=opts.txtField
            ,valField=opts.valField;
        var txtArr=[],valArr=[],dataArr=[];// 选中项文本，值，数据
        var len=opts.mulChk?chkEls.length:Math.min(chkEls.length,1);
        for(var i= 0,dataI;i<len;i++){
            dataI=parseInt(chkEls.eq(i).val(),10);
            selIdx.push(dataI);
            txtArr.push(_data[dataI][txtField]);
            valArr.push(_data[dataI][valField]);
            dataArr.push(_data[dataI]);
        }
        el.val(txtArr.join(';'));
        el.attr('title',txtArr.join(';'));
        hideEl.val(valArr.join(';'));
        opts.callback && opts.callback(opts.mulChk?dataArr:dataArr[0]);// 修改选中项时的回调
    };
    var _getSelect=function(){
        var selData=[];
        for(var i= 0;i<selIdx.length;i++){
            selData.push(_data[selIdx[i]]);
        }
        return opts.mulChk ? selData : selData[0];
    };
    // 根据 selIdx 选中 dom
    var _checkDom=function(){
        var chkEls=dpEl.find('[name="'+opts.name+'"]');
        chkEls.prop('checked',false);
        for(var i= 0,dataI;i<selIdx.length;i++){
            dataI=selIdx[i];
            chkEls.filter('[value="'+dataI+'"]').prop('checked',true);
        }
    };
    /**
     * 改变符合条件的数据源的选中状态，并更新到 dom 和 selIdx
     * @param key {string=} 键
     * @param val {string|Array|undefined=} 值
     * @param check {boolean=} 选中 true / 取消选中 false，默认为 true
     * @private
     */
    var _check=function(key,val,check){
        var chkEls=dpEl.find('[name="'+opts.name+'"]');
        if(check==undefined) check=true;
        var valIsArr=(Object.prototype.toString.call(val) === '[object Array]');// 是否是数组
        for(var i= 0,item;i<_data.length;i++){
            item=_data[i];
            if(!valIsArr && item[key]==val || valIsArr && val.indexOf(item[key])!=-1){
                chkEls.filter('[value="'+i+'"]').prop('checked',check);
            }
        }
        _refreshSelIdx();
    };
    // 复选时的按钮操作：全选 true / 全不选 false - 只供组件内按钮操作，不刷新选中项索引列表（点取消时不保存）
    var _checkAll=function(check){
        if(!opts.mulChk) return;
        var chkEls=dpEl.find('[name="'+opts.name+'"]');
        chkEls.prop('checked',check);
    };
    // 修改数据源并根据 selParams 重置默认选中值
    var _setData=function(data,selParams){
        if(data) _data=$.extend([],data);
        var str='';
        var inputType = opts.mulChk ? 'checkbox' : 'radio'
            ,name=opts.name
            ,txtField=opts.txtField;
        for(var i= 0,opt;i<_data.length;i++){
            opt=_data[i];
            str+='<li><label class="dropSel-label"><input type="'+inputType+'" name="'+name+'" value="'+i+'" />'+$.encodeHtml(opt[txtField])+'</label></li>';
        }
        dpEl.find('ul.dropSel-ul').html(str);
        if(_filterObj){// 更新过滤组件数据源
            _filterObj.setData(_data);
        }
        if(selParams){
            _check(selParams[0],selParams[1],true);
        }else{
            _refreshSelIdx();// 直接刷新 selIdx
        }
    };
    var _init=function(){
        var oFilterOpts = opts.filter;
        // 下拉框内容主体字符串
        var getDropStr=function(){
            var str='<div class="dropdown dropSel '+ opts.cusCls +'">';
            var boxH=opts.height-CONF.emptyH,
                boxW=opts.width;
            if(oFilterOpts){
                boxH-=30;
                str+='<input class="dropSel-filter" value="" />';
            }
            str+='<div class="dropSel-box" style="'+(boxW?'width:'+boxW+'px;':'')+'height: '+boxH+'px;"><ul class="dropSel-ul"></ul></div>'+
                '<div class="dropSel-tool">';
            if(opts.mulChk){
                str+='<button class="dropSel-btn" style="float:left;" data-val="all">全选</button>'+
                    '<button class="dropSel-btn" style="float:left;margin-left:2px;" data-val="allno">清空</button>';
            }
            str+='<button class="dropSel-btn" style="margin-left:2px;" data-val="close">取消</button>'+
                '<button class="dropSel-btn dropSel-btn-success" data-val="enter">确定</button>'+
                '</div></div>';
            return str;
        };
        // 下拉框中的内容部分
        dpEl=$(getDropStr());
        if(oFilterOpts){
            !oFilterOpts.fields && (oFilterOpts.fields=opts.txtField);
            _filterObj=dpEl.find('.dropSel-filter').initFilter($.extend({
                data:_data
                ,afterFilter:function(newData,keyword){// 高亮
                    var jqUl = dpEl.find('.dropSel-ul'),
                        jqsChk = jqUl.find('[name="'+opts.name+'"]'),
                        sHighCls = 'dropSel-high';// 高亮样式
                    var i,len,jqLi;
                    dpEl.find('li').removeClass(sHighCls);// 移除全部高亮样式
                    if(opts.filterPrepose){// 需要前置匹配项
                        for(i=0, len=_data.length; i<_data.length; i++){
                            jqUl.append( jqsChk.filter('[value="'+i+'"]').closest('li'));
                        }
                        if(keyword!=''){// 关键字非空，过滤匹配的元素提前，由于使用 prepend，所以从匹配的最后一项开始遍历并插入 dom，以保证显示顺序
                            for(i=newData.length-1;i>=0;i--){
                                jqLi = jqsChk.filter('[value="'+_data.indexOf(newData[i])+'"]').closest('li');
                                jqLi.addClass(sHighCls);
                                jqUl.prepend(jqLi);
                            }
                        }
                    }else{// 不需要前置，直接高亮匹配项
                        if(keyword!=''){
                            for(i=0,len=newData.length;i<len;i++){
                                dpEl.find('[value="'+_data.indexOf(newData[i])+'"]').closest('li').addClass('dropSel-high');
                            }
                        }
                    }
                }
            },opts.filter));
        }
        hideEl=$('<input type="hidden" name="'+opts.name+'" />');
        el.prop('readonly',true)// 禁止输入
          .attr('autocomplete','off')
          .after(hideEl);// 添加隐藏域
        _setData(opts.data,opts.selParams);
        dpEl.on('click.dpSel','[data-val]',function(){// 操作按钮
            if(!dpObj) return;
            var ctrlVal=$(this).attr('data-val');
            if(ctrlVal=='enter'){// 确定 - 获取选中值，然后关闭
                _refreshSelIdx();
                dpObj.close();
            }else if(ctrlVal=='close'){// 取消 - 还原选中状态，然后关闭
                dpObj.close();
            }else if(ctrlVal=='all'){// 全选
                _checkAll(true);
            }else if(ctrlVal=='allno'){// 不选
                _checkAll(false);
            }
        });
        dpObj=el.dropdown($.extend(
            {
                modal: false
            },
            opts.dpOpts,
            {
                cont: dpEl,
                noDestroy: true,
                show: false,
                beforeClose: function(){
                    _checkDom();
                },
                beforeShow: $.noop
            }
        ));
        el.off('click.showDp').on('click.showDp',function(){
            if(dpObj && !dpObj.isShown()) dpObj.show();
        });
    };
    returnObj={
        getSelect:_getSelect,// 获取选中值，单选时返回对象，多选时返回数组
        check:_check,// 改变符合条件的数据源的选中状态，并更新到 dom 和 selIdx
        setData:_setData// 重置数据源
    };
    _init();
    return returnObj;
};